package com.credithc.signature.job.handler;

import com.alibaba.fastjson.JSONObject;
import com.credithc.signature.common.constant.Constant;
import com.credithc.signature.common.po.SealInfo;
import com.credithc.signature.common.ro.NewSignProviderReq;
import com.credithc.signature.common.ro.OldSignProviderReq;
import com.credithc.signature.common.service.SealInfoService;
import com.credithc.signature.common.service.SignatureLogService;
import com.credithc.signature.common.utils.DateUtil;
import com.credithc.signature.common.utils.HttpUploadUtil;
import com.credithc.signature.common.utils.MessageFilterUtil;
import com.credithc.signature.common.utils.UUIDUtil;
import com.credithc.signature.job.configure.props.SignatureProps;
import com.credithc.signature.job.ro.CallRequest;
import com.credithc.signature.job.ro.HandleRequest;
import com.credithc.signature.job.ro.JobRequest;
import com.credithc.signature.job.service.GeneratePDFService;
import com.credithc.signature.job.service.SignatureService;
import com.credithc.signature.job.service.UploadPDFService;
import com.credithc.signature.job.utils.PathUtil;
import com.credithc.signature.job.utils.PdfStampUtil;
import com.credithc.signature.job.utils.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * @desc: <br/>
 * @author: Jingbo Hu<br/>
 * @time：2021年06⽉25⽇<br/>
 * @version：v1.0.0<br>
 */
@Slf4j
public class GenerateFileHandler extends AbstractExecuteHandler {

    private String handlerName = "生成合同";

    @Autowired
    private static SignatureProps props;

    @Autowired
    private static GeneratePDFService generatePdfService;

    @Autowired
    private static UploadPDFService uploadPDFService;

    @Autowired
    private static SignatureService signatureService;

    @Autowired
    private static SignatureLogService signatureLogService;

    @Autowired
    private static SealInfoService sealInfoService;


    static {
        generatePdfService = SpringUtil.getBean(GeneratePDFService.class);
        uploadPDFService = SpringUtil.getBean(UploadPDFService.class);
        signatureService = SpringUtil.getBean(SignatureService.class);
        signatureLogService = SpringUtil.getBean(SignatureLogService.class);
        sealInfoService = SpringUtil.getBean(SealInfoService.class);
        props = SpringUtil.getBean(SignatureProps.class);
    }

    /**
     * 设置HandlerName
     */
    public GenerateFileHandler() {
        this.handlerName = handlerName;
    }


    @Override
    public void handleRequest(HandleRequest handleRequest) throws Exception {
        if (Objects.nonNull(handleRequest)) {
            JobRequest jobRequest = handleRequest.getJobRequest();
            String requestSn = jobRequest.getRequestSn();
            // 1.序列化消息
            List<Map<String, String>> certInfos = new ArrayList<>();
            Map<String, List<Map<String, Object>>> listData = new HashMap<>(16);
            Map<String, String> otherData = new HashMap<>(16);
            List<String> sealCodes = null;
            try {
                sealCodes = decodeJsonBody(handleRequest.getJobRequest().getJsonBody(), certInfos, listData, otherData, sealCodes);

                // 2.生成PDF
                String pdfPath = generatePdf(handleRequest.getJobRequest(), listData, otherData, sealCodes);
                log.info("－消息－:requestSn={},【{}】已经处理;流程结束", requestSn, handlerName);

                // 3.载入下一流程参数
                handleRequest.setSealCodes(sealCodes);
                handleRequest.setPdfPath(pdfPath);
                handleRequest.setCertInfos(certInfos);

                // 4、判断是否有下一个
                hasNextHandler(requestSn, handleRequest);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("－消息－:requestSn={},执行【{}】流程时发生异常;总流程结束\n{}", requestSn, handlerName, e.getCause());
                this.setNextHandler(new CallbackHandler());
                CallRequest callRequest = new CallRequest();
                BeanUtils.copyProperties(jobRequest,callRequest);
                callRequest.setCallBackURL(jobRequest.getCallbackUrl());
                callRequest.setRequestSN(requestSn);
                callRequest.setIsSuccess(false);
                callRequest.setErrorMsg(e.getMessage());
                handleRequest.setCallRequest(callRequest);
                this.nextHandler.handleRequest(handleRequest);
            }
        }
    }

    /**
     * 判断是否还有下一个流程:如果有，则继续执行
     */
    private void hasNextHandler(String requestSn, HandleRequest handleRequest) throws Exception {
        if (null != this.nextHandler) {
            this.nextHandler.handleRequest(handleRequest);
        } else {
            log.info("－消息－:requestSn={},【{}】无下一个执行流程;流程结束", requestSn, handlerName);
            return;
        }
    }

    /**
     * 生成PDF合同
     *
     * @param coreRequet
     * @param listData
     * @param otherData
     * @param sealCodes
     * @return
     * @throws Exception
     */
    public String generatePdf(JobRequest coreRequet, Map<String, List<Map<String, Object>>> listData, Map<String, String> otherData, List<String> sealCodes) throws Exception {
        try {
            //1.检查是否需要分开签：就是已经签完的合同，想再次签章
            NewSignProviderReq newSignProviderReq = JSONObject.parseObject(coreRequet.getJsonBody(), NewSignProviderReq.class);
            if (newSignProviderReq.getSeparateSign() != null) {
                Map<String, String> separateMap = newSignProviderReq.getSeparateSign();
                String contractUri = separateMap.get("contractUri");
                String sealCode = separateMap.get("sealCode");
                String keyWord = separateMap.get("keyWord");
                //a.下载合同
                String snapPDFPath = PathUtil.getSnapPDFPath(props.snapNoSignPdf, coreRequet.getRequestSn());
                HttpUploadUtil.download(props.downloadUrl, contractUri, snapPDFPath);

                //b.添加公章关键字
                SealInfo sealInfo = sealInfoService.selectBySealCode(sealCode);
                String addWords = sealInfo.getKeyWords();
                sealCodes = new ArrayList<>();
                sealCodes.add(sealCode);

                String uuid = UUIDUtil.getUUID();
                String destFileName = Constant.SNAP_PDF_PREFIX + uuid + Constant.PDF_EXT;
                String date = DateUtil.getStandardDateStr();
                String signSnapPDFPath = PathUtil.getSignSnapPDFPath(props.snapSignPdf, destFileName, date);

                PdfStampUtil.findKeyWordAndAddWords(snapPDFPath, signSnapPDFPath, keyWord, addWords);
                //刪除之前的合同文件
                uploadPDFService.removeUnusedFile(snapPDFPath);
                return signSnapPDFPath;
            } else {
                //正常生成合同
                long start = System.currentTimeMillis();
                String noSignPath = generatePdfService.generatePDFToDisk(coreRequet, listData, otherData);
                long end = System.currentTimeMillis();
                log.debug("－消息－: requestSn={},生成PDF成功,耗时:{}毫秒", coreRequet.getRequestSn(), (end - start));
                return noSignPath;
            }
        } catch (Exception e) {
            String errorMsg = MessageFilterUtil.limitLength(e.getMessage());
            signatureLogService.updateResult(errorMsg, coreRequet.getRequestSn());
            log.error("－消息－: requestSn={},生成PDF失败,", coreRequet.getRequestSn(), e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 解包jsonBody
     *
     * @param jsonBody
     * @param certInfos
     * @param listData
     * @param otherData
     */
    private List<String> decodeJsonBody(String jsonBody, List<Map<String, String>> certInfos,
                                        Map<String, List<Map<String, Object>>> listData, Map<String, String> otherData, List<String> sealCodes) {
        boolean isNewSignature = true;
        if (jsonBody.contains("singnalElement") || jsonBody.contains("singnalElement") || jsonBody.contains("singnalElement")) {
            isNewSignature = false;
        }
        if (isNewSignature) {
            NewSignProviderReq newSignProviderReq = JSONObject.parseObject(jsonBody, NewSignProviderReq.class);
            if (newSignProviderReq.getCertInfos() != null) {
                certInfos.addAll(newSignProviderReq.getCertInfos());
            }
            if (newSignProviderReq.getListData() != null) {
                listData.putAll(newSignProviderReq.getListData());
            }
            if (newSignProviderReq.getOtherData() != null) {
                otherData.putAll(newSignProviderReq.getOtherData());
            }
            if (newSignProviderReq.getOfficialSealsCodes() != null) {
                sealCodes = new ArrayList<>();
                sealCodes.addAll(newSignProviderReq.getOfficialSealsCodes());

            }
        } else {
            OldSignProviderReq oldSignProviderReq = JSONObject.parseObject(jsonBody, OldSignProviderReq.class);
            if (oldSignProviderReq.getCertApplys() != null) {
                certInfos.addAll(oldSignProviderReq.getCertApplys());
            }
            if (oldSignProviderReq.getListElements() != null) {
                listData.putAll(oldSignProviderReq.getListElements());
            }
            if (oldSignProviderReq.getSingnalElement() != null) {
                otherData.putAll(oldSignProviderReq.getSingnalElement());
            }
            if (oldSignProviderReq.getOfficialSealsCodes() != null) {
                sealCodes = new ArrayList<>();
                sealCodes.addAll(oldSignProviderReq.getOfficialSealsCodes());
            }
        }
        // 实际中发现有的系统传idCardTypeCode，有的系统传idTypeCode，需要做非空判断
        certInfos.stream().forEach(cert -> {
            String idCardTypeCode = cert.get("idCardTypeCode");
            if (StringUtils.isNotBlank(idCardTypeCode)) {
                cert.put("idTypeCode", idCardTypeCode);
            } else {
                String idTypeCode = cert.get("idTypeCode");
                if (StringUtils.isBlank(idTypeCode)) {
                    cert.put("idTypeCode", Constant.MAINLAND_ID);
                }
            }
        });
        return sealCodes;
    }

}
